//
// Created by marcel on 07.08.19.
//

#ifndef FICTION_QCC_WRITER_H
#define FICTION_QCC_WRITER_H

#include "fcn_cell_layout.h"
#include "fmt/format.h"
#include "fmt/ostream.h"
#include "version_info.h"
#include <boost/filesystem.hpp>
#include <itertools.hpp>
#include <string>
#include <sstream>
#include <unordered_set>

namespace qcc
{
    constexpr const char* VERSION_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                                           "<!--File describing the QCA component-->\n"
                                           "<!--Generated by {} ({})-->\n";

    constexpr const char* OPEN_QCA_COMPONENT = "<qcacomponent Version=\"2\" tech=\"{}\" lib=\"{}\" name=\"{}\" "
                                               "ID=\"{}\" function=\"\" maxX=\"{}\" maxY=\"{}\" MagnetsCount=\"{}\">\n";
    constexpr const char* CLOSE_QCA_COMPONENT = "</qcacomponent>";  // no new line to use std::endl to flush stream

    constexpr const char* LIBRARY_NAME = "components_fiction";

    constexpr const char* OPEN_ENTITY = "\t<entity>\n";
    constexpr const char* CLOSE_ENTITY = "\t</entity>\n";
    constexpr const char* OPEN_COMPONENTS = "\t<components>\n";
    constexpr const char* CLOSE_COMPONENTS = "\t</components>\n";
    constexpr const char* OPEN_LAYOUT = "\t<layout>\n";
    constexpr const char* CLOSE_LAYOUT = "\t</layout>\n";

    constexpr const char* PIN = "\t\t<pin tech=\"{}\" name=\"{}\" direction=\"{}\" x=\"{}\" y=\"{}\"/>\n";
    constexpr const char* COMPONENT_ITEM = "\t\t<item tech=\"{}\" name=\"{}\"/>\n";

    constexpr const char* OPEN_LAYOUT_ITEM = "\t\t<item comp=\"{}\" x=\"{}\" y=\"{}\">\n";
    constexpr const char* CLOSE_LAYOUT_ITEM = "\t\t</item>\n";

    constexpr const char* LAYOUT_ITEM_PROPERTY = "\t\t\t<property name=\"{}\" value=\"{}\"/>\n";
    constexpr const char* PROPERTY_PHASE = "phase";
    constexpr const char* PROPERTY_LENGTH = "length";


    const std::vector<std::string> components{"Magnet", "Coupler", "Cross Wire", "And", "Inverter", "Or"};
    const std::map<fcn::cell_type, unsigned> component_selector
    {
        {fcn::NORMAL_CELL, 0},
        {fcn::INPUT_CELL, 0},
        {fcn::OUTPUT_CELL, 0},
        {fcn::inml::FANOUT_COUPLER_MAGNET, 1},
        {fcn::inml::CROSSWIRE_MAGNET, 2},
        {fcn::inml::SLANTED_EDGE_DOWN_MAGNET, 3},
        {fcn::inml::INVERTER_MAGNET, 4},
        {fcn::inml::SLANTED_EDGE_UP_MAGNET, 5},
    };

    /**
     * Writes an fcn_cell_layout to a file readable by ToPoliNano and MagCAD (https://topolinano.polito.it/).
     *
     * @param fcl Cell layout to be written.
     * @param filename Desired file name of file to write fcl into. Should end with ".qcc" (without quotes).
     * @param comp_name Flag to indicate that the given filename should be used as the component's identifier.
     */
    void write(fcn_cell_layout_ptr fcl, const std::string& filename, const bool comp_name = false);
}


#endif //FICTION_QCC_WRITER_H
